perm filename FILES.MSS[WHT,LSP] blob sn#754060 filedate 1984-05-12 generic text, type T, neo UTF8
@Part[Files, Root = "CLM.MSS"]
@Comment{Chapter of Common Lisp Manual.  Copyright 1984 Guy L. Steele Jr.⎇


@MyChapter[File System Interface]
@label[FILES]

A frequent use of streams is to communicate with a @i[file system]
to which groups of data (files) can be written and from which files
can be retrieved.

@clisp defines a standard interface for dealing with such a file system.
This interface is designed to be simple and general enough to
accommodate the facilities provided by ``typical'' operating system
environments within which @clisp is likely to be implemented.
The goal is to make @clisp programs that perform only simple operations
on files reasonably portable.

To this end, @clisp assumes that files are named, that given a name one
can construct a stream connected to a file of that name, and that the
names can be fit into a certain canonical, implementation-independent
form called a @i[pathname].

Facilities are provided for manipulating pathnames, for creating
streams connected to files, and for manipulating the file system
through pathnames and streams.

@Section [File Names]

@clisp programs need to use names to designate files.
The main difficulty in dealing with names of files is that different
file systems have different naming formats for files.
For example, here is a table of several file systems (actually,
operating systems that provide file systems) and what equivalent
file names might look like for each one:
@Begin[Format,Leftmargin +1.5 in]
@Tabset[+1 in]
@ux[System@\File name@Hsp[2 in]]
@c[tops-20]@\@f{<LISPIO>FORMAT.FASL.13⎇
@c[tops-10]@\@f{FORMAT.FAS@lbracket@;1,4@rbracket@;⎇
@c[its]@\@f{LISPIO;FORMAT FASL⎇
@c[multics]@\@f{>udd>LispIO>format.fasl⎇
@c[tenex]@\@f{<LISPIO>FORMAT.FASL;13⎇
@c[vax]/@c[vms]@\@f{@lbracket@;LISPIO@rbracket@;FORMAT.FAS;13⎇
@c[unix]@\@f{/usr/lispio/format.fasl⎇
@End[Format]
It would be impossible for each program that deals with file names to
know about each different file name format that exists; a new @clisp
implementation might use a format different from any of its predecessors.
Therefore, @clisp provides @i[two] ways to represent file names:
@i[namestrings], which are strings in the implementation-dependent form
customary for the file system, and @i[pathnames], which are special
data objects that represent file names in an implementation-independent
way.  Functions are provided to convert between these two representations,
and all manipulations of files can be expressed in machine-independent
terms by using pathnames.

In order to allow @clisp programs to operate in a network environment
that may have more than one kind of file system, the pathname facility
allows a file name to specify which file system is to be used.
In this context, each file system is called a @i[host], in keeping
with the usual networking terminology.

@Subsection[Pathnames]
@label[PATHNAME]
All file systems dealt with by @clisp are forced into a common framework,
in which files are named by a @xlisp data object of type @f[pathname].

A pathname always has six components, described below.  These components
are the common interface that allows programs to work the same way with
different file systems; the mapping of the pathname components into the
concepts peculiar to each file system is taken care of by the @clisp
implementation.


@Begin[Description]
@i[host]@\@Index[host (pathname component)]@}
The name of the file system on which the file resides.

@i[device]@\@Index[device (pathname component)]@}
Corresponds to the ``device'' or ``file structure'' concept in many
host file systems: the name of a (logical or physical) device containing files.

@i[directory]@\@Index[directory (pathname component)]@}
Corresponds to the ``directory'' concept in many host file systems:
the name of a group of related files (typically those belonging to a single
user or project).

@i[name]@\@Index[name (pathname component)]@}
The name of a group of files that can be thought of as
conceptually the ``same'' file.

@i[type]@\@Index[type (pathname component)]@}
Corresponds to the ``filetype'' or ``extension'' concept in many host
file systems.  This says what kind of file this is.  Files with the same name
but different type are usually related in some specific way, such as
one being a source file, another the compiled form of that source,
and a third the listing of error messages from the compiler.

@i[version]@\@Index[version (pathname component)]@}
Corresponds to the ``version number'' concept in many host file systems.
Typically this is a number that is incremented every time the file is modified.
@End[Description]

Note that a pathname is not necessarily the name of a specific file.
Rather, it is a specification (possibly only a partial specification) of
how to access a file.  A pathname need not correspond to any file that
actually exists, and more than one pathname can refer to the same file.
For example, the pathname with a version of ``newest'' may refer to the
same file as a pathname with the same components except a certain number
as the version.  Indeed, a pathname with version ``newest'' may refer to
different files as time passes, because the meaning of such a pathname
depends on the state of the file system.  In file systems with such
facilities as ``links,'' multiple file names, logical devices, and so on,
two pathnames that look quite different may turn out to address the same
file.  To access a file given a pathname, one must do a file system
operation such as
@Funref[open].

@Index2[P {parsing⎇, S {of pathnames⎇]
@Index2[P {merging⎇, S {of pathnames⎇]
Two important operations involving pathnames are @i[parsing] and
@i[merging].  Parsing is the conversion of a namestring (which might be
something supplied interactively by the user when asked to supply the
name of a file) into a pathname object.  This operation is
implementation-dependent, because the format of namestrings
is implementation-dependent.
Merging takes a pathname with missing components
and supplies values for those components from a source of defaults.

Not all of the components of a pathname need to be specified.  If a
component of a pathname is missing, its value is @nil.  Before the file
system interface can do anything interesting with a file, such as opening the
file, all the missing components of a pathname must be filled in
(typically from a set of defaults).  Pathnames with missing components
may be used internally for various purposes;
in particular, parsing a namestring
that does not specify certain components will result in a pathname with
missing components.

A component of a pathname can also be the keyword @Kwd[wild].
This is only useful when the pathname is being used with a
directory-manipulating operation, where it means that the pathname
component matches anything.  The printed representation of a pathname
typically designates @Kwd[wild] by an asterisk; however, this is
host-dependent.

What values are allowed for components of a pathname depends, in general,
on the pathname's host.  However, in order for pathnames to be usable
in a system-independent way, certain global conventions are adhered to.
These conventions are stronger for the type and version than for the
other components, since the type and version are explicitly manipulated by
many programs, while the other components are usually treated as something
supplied by the user that just needs to be remembered and copied
from place to place.

The type is always a string or @nil or @Kwd[wild].
It is expected that most
programs that deal with files will supply a default type for each file.

The version is either a positive integer or a special symbol.  The
meanings of @nil and @Kwd[wild] have been explained
above.  The keyword @Kwd[newest] refers to the largest version number
that already exists in the file system when reading a file, or to
a version number
greater than any already existing in the file system
when writing a new file.  Some @clisp implementors
may choose to define other special version symbols.
Some semi-standard names, suggested but not required to be supported
by every @clisp implementation, are
@Kwd[oldest], to refer to the smallest version number that exists
in the file system;
@Kwd[previous], to refer to the version previous to the newest version;
and @Kwd[installed], to refer to a version that is officially installed
for users (as opposed to a working or development version.
Some @clisp implementors may also choose to attach a meaning to
non-positive version numbers (a typical convention is that @f[0]
is synonymous with @Kwd[newest] and @f[-1] with @Kwd[previous]),
but such interpretations are implementation-dependent.

The host may be a string, indicating a file system, or a list
of strings, of which the first names the file system and the rest
may be used for such a purpose as inter-network routing.

@Index[structured pathname components]
The device, directory, and name can each be a string (with
host-dependent rules on allowed characters and length) or possibly
some other @clisp data structure
(in which case such a component is said to be @i[structured]
and has an implementation-dependent format).
Structured components may be used to handle such file system features as
hierarchical directories.  @clisp programs do not need to know about
structured components unless they do host-dependent operations.
Specifying a string as a pathname component for a host that requires a
structured component will cause conversion of the string to the appropriate
form.

The best way to compare two pathnames for equality is with @Funref[equal],
not @f[eql].
(On pathnames, @f[eql] is simply the same as @f[eq].)
Two pathname objects are @f[equal] if and only if
all the corresponding components
(host, device, and so on) are equivalent.  (Whether or not
uppercase and lowercase letters are considered equivalent
in strings appearing in components depends on the file
name conventions of the file system.)  Pathnames
that are @f[equal] should be functionally equivalent.

Some host file systems have features that do not fit into this pathname
model.  For instance, directories might be accessible as files; there
might be complicated structure in the directories or names; or there
might be a way to specify a directory relative to a
``current'' directory, such as the @f[<] syntax in
@c[multics] or the special ``@f[..]'' file name of @c[unix].  Such
features are not allowed for by the standard @clisp file system
interface.  An implementation is free to accommodate such features in its
pathname representation and provide a parser that can process such
specifications in namestrings; such features are then likely to work
within that single implementation.  However, note that once a program
depends explicitly on any such features, it will not be portable.

@Subsection[Pathname Functions]

These functions are what programs use to parse and default file names
that have been typed in or otherwise supplied by the user.

Any argument called @i[pathname] in this manual may actually be a pathname,
a string or symbol, or a stream.  Any argument called @i[defaults] may
likewise be a pathname, a string or symbol, or a stream.

In the examples, it is assumed that the host named @f[CMUC] runs
the @c[tops-20] operating system, and therefore uses @c[tops-20]
file system syntax; furthermore, an explicit host name is
indicated by following the host name with a double colon.
Remember, however, that namestring syntax is implementation-dependent,
and this syntax is used here purely for the sake of examples.

@Defun[Fun {pathname⎇, Args {@i[pathname]⎇]
The @f[pathname] function converts its argument to be a pathname.
The argument may be a pathname, a string or symbol, or a stream;
the result is always a pathname.
@Enddefun

@Defun[Fun {truename⎇, Args {@i[pathname]⎇]
The @f[truename] function
endeavors to discover the ``true name'' of the file
associated with the @i[pathname] within the file system.
If the @i[pathname] is an open stream already associated with a file
in the file system, that file is used.
The ``true name'' is returned as a pathname.
An error is signalled if an appropriate file cannot be located
within the file system for the given @i[pathname].

The @f[truename] function may be used to
account for any file-name translations performed by the file system,
for example.

For example, suppose that @f[DOC:] is a @c[tops-20] logical
device name that is translated by the @c[tops-20] file system
to be @f[PS:<DOCUMENTATION>].
@Lisp
(setq file (open "CMUC::DOC:DUMPER.HLP"))
(namestring (pathname file)) @ev "CMUC::DOC:DUMPER.HLP"
(namestring (truename file))
   @ev "CMUC::PS:<DOCUMENTATION>DUMPER.HLP.13"
@Endlisp
@Enddefun

@Defun[Fun {parse-namestring⎇, Args {@i[thing] @optional @i[host] @i[defaults]⎇, Keys {[start][end]⎇, MoreKeys {[junk-allowed]⎇]
This turns @i[thing] into a pathname.  The @i[thing] is usually a string
(that is, a namestring), but it may be a symbol (in which case the print
name is used) or a pathname or stream
(in which case no parsing is needed, but
an error check may be made for matching hosts).

This function does @i[not], in general, do defaulting of pathname components,
even though it has an argument named @i[defaults];
it only does parsing.  The
@i[host] and @i[defaults] arguments are present because in some implementations
it may be that a namestring can only be parsed with reference to a
particular file name syntax of several available in the implementation.
If @i[host] is
non-@nil, it must be a host name that could appear in the
host component of a pathname, or @nil;
if @i[host] is @nil then the host 
name is extracted from the default pathname in @i[defaults]
and used to determine the syntax convention.  The @i[defaults] argument
defaults to the value of @Varref[default-pathname-defaults].

For a string (or symbol) argument, @f[parse-namestring]
parses a file name within it in the
range delimited by the @kwd[start] and @kwd[end] arguments
(which are integer indices
into @i[string], defaulting to the beginning and end of the string).

If @kwd[junk-allowed] is not @false, then the first value
returned is the pathname parsed, or @false if no syntactically correct
pathname was seen.

If @kwd[junk-allowed] is @false (the default),
then the entire substring is scanned.
The returned value is the pathname parsed.
An error is signalled if the substring does not consist entirely of
the representation of a pathname, possibly surrounded on either side by
whitespace characters if that is appropriate to the cultural conventions
of the implementation.

In either case, the second value is the index into the string of the delimiter
that terminated the parse, or the index beyond the substring if the
parse terminated at the end of the substring (as will always be the case if
@kwd[junk-allowed] is false).

If @i[thing] is not a string or symbol, then @i[start] (which defaults
to zero in any case) is always returned as the second value.

Parsing an empty string always succeeds, producing a pathname with
all components (except the host) equal to @nil.

Note that if @i[host] is specified and not @nil,
and @i[thing] contains a manifest host name, an
error is signalled if the hosts do not match.

If @i[thing] contains an explicit host name and no explicit device name,
then it may be appropriate, depending on the
implementation environment, for @f[parse-namestring] to supply the
standard default device for that host as the device component
of the resulting pathname.
@Enddefun

@Defun[Fun {merge-pathnames⎇, Args {@i[pathname] @optional @i[defaults] @i[default-version]⎇]
This is the function that most programs should call to process a file
name supplied by the user.  It fills in unspecified components of
@i[pathname] from the @i[defaults], and returns a new pathname.  The
@i[pathname] and @i[defaults] arguments may each
be a pathname, stream, string, or symbol.  The
returned value will always be a pathname.

@i[defaults] defaults to the value of @Varref[default-pathname-defaults].
@i[default-version] defaults to @Kwd[newest].

Here is an example of the use of @f[merge-pathnames]:
@Lisp
(merge-pathnames "CMUC::FORMAT"
		 "CMUC::PS:<LISPIO>.FASL")
   @EV @r[a pathname object that re-expressed as a namestring would be]
      "CMUC::PS:<LISPIO>FORMAT.FASL.0"
@Endlisp

Defaulting of pathname components is done by filling in components taken
from another pathname.
This is especially useful for
cases such as a program that has an input file and an output file, and
asks the user for the name of both, letting the unsupplied components of
one name default from the other.  Unspecified components of the output
pathname will come from the input pathname, except that the type should
default not to the type of the input but to the appropriate default type
for output from this program.

The pathname merging operation takes as input a given pathname, a
defaults pathname, and a default version, and returns a
new pathname.  Basically, the missing components in the given pathname
are filled in from the defaults pathname, except that
if no version is specified the
default version is used.
The default version is usually @Kwd[newest]; if no version is specified
the newest version in existence should be used.  The default
version can be @nil, to preserve the information that it was missing
in the input pathname.

If the
given pathname explicitly specifies a host and does not supply a device, then
if the host component of the defaults matches the host component
of the given pathname, then the device is taken from the defaults;
otherwise
the device will be the default file device for that host.  Next, if
the
given pathname does not specify a host, device, directory, name,
or type, each such
component is copied from the defaults.
The merging rules for the version are more complicated and
depend on whether the pathname specifies a name.  If the pathname
doesn't specify a name, then the version, if not provided, will
come from the defaults, just like the other components.  However, if the
pathname does specify a name, then the version is not affected
by the defaults.  The reason is that the version
``belongs to'' some other file name and is unlikely to have anything to do
with the new one.  Finally, if this process leaves the
version missing, the default version is used.

The net effect is that if the user supplies just a name, then the
host, device, directory, and type will come from the defaults, but the
version will come from the default version
argument to the merging operation.  If the user supplies nothing, or
just a directory, the name, type, and version will come over from
the defaults together.  If the host's file name syntax provides a way
to input a version without a name or type, the user can let the name
and type
default but supply a version different from the one in the defaults.
@Enddefun

@Defvar[Var {default-pathname-defaults⎇]
This is the default pathname-defaults pathname; if any pathname primitive
that needs a set of defaults is not given one, it uses this one.
As a general rule, however, each program
should have its own pathname defaults rather than using this one.
@Enddefvar

@Defun[Fun {make-pathname⎇, Keys {[host][device][directory][name]⎇, Morekeys = {[type][version][defaults]⎇]
Given some components, @f[make-pathname]
constructs and returns a pathname.  After the components specified
explicitly by the @Kwd[host], @Kwd[device], @Kwd[directory],
@Kwd[name], @Kwd[type], and @Kwd[version] arguments are filled in,
the merging rules used by @Funref[merge-pathnames] are used to fill
in any missing components from the defaults specified by the
@Kwd[defaults] argument.
The default value of the
@Kwd[defaults] argument is a pathname whose host component
is the same as the host component of the value of
@Varref[default-pathname-defaults], and whose other components
are all @nil.

Whenever a pathname is constructed, whether by @f[make-pathname] or some
other function, the components may be canonicalized if appropriate.
For example, if a file system is insensitive to case, then
alphabetic characters may be forced to be all uppercase or all lowercase
by the implementation.
@Enddefun

@Defun[Fun {pathnamep⎇, Args {@i[object]⎇]
This predicate is true if @i[object] is a pathname, and otherwise is false.
@Lisp
(pathnamep x) @EQ (typep x 'pathname)
@Endlisp
@Enddefun

@Defun[Fun {pathname-host⎇, Args {@i[pathname]⎇]
@Defun1[Fun {pathname-device⎇, Args {@i[pathname]⎇]
@Defun1[Fun {pathname-directory⎇, Args {@i[pathname]⎇]
@Defun1[Fun {pathname-name⎇, Args {@i[pathname]⎇]
@Defun1[Fun {pathname-type⎇, Args {@i[pathname]⎇]
@Defun1[Fun {pathname-version⎇, Args {@i[pathname]⎇]
These return the components of the argument @i[pathname], which may be a
pathname, string or symbol, or stream.
The returned values can be strings, special
symbols, or some other object in the case of structured components.  The
type will always be a string or a symbol.  The version will always be a
number or a symbol.
@Enddefun

@Defun[Fun {namestring⎇, Args {@i[pathname]⎇]
@Defun1[Fun {file-namestring⎇, Args {@i[pathname]⎇]
@Defun1[Fun {directory-namestring⎇, Args {@i[pathname]⎇]
@Defun1[Fun {host-namestring⎇, Args {@i[pathname]⎇]
@Defun1[Fun {enough-namestring⎇, Args {@i[pathname] @optional @i[defaults]⎇]
The @i[pathname] argument may be a pathname, a string or symbol,
or a stream that is or was open to a file.
The name represented by @i[pathname] is returned as a namelist
in canonical form.

If @i[pathname] is a stream, the name returned represents the
name used to @i[open] the file, which may not be the @i[actual]
name of the file (see @Funref[truename]).

@f[namestring] returns the full form of the @i[pathname] as a string.
@f[file-namestring] returns a string representing just the @i[name],
@i[type], and @i[version] components of the @i[pathname];
the result of @f[directory-namestring]
represents just the @i[directory-name] portion; and @f[host-namestring]
returns a string for just the @i[host-name] portion.
Note that a valid namestring cannot necessarily be constructed
simply by concatenating some of the three shorter strings in some order.

@f[enough-namestring] takes another argument, @i[defaults].
It returns an abbreviated namestring that is just sufficient to
identify the file named by @i[pathname] when considered relative
to the @i[defaults] (which defaults to the value of
@Varref[default-pathname-defaults]).  That is, it is required
that
@Lisp
(merge-pathnames (enough-namestring @i[pathname] @i[defaults])
		 @i[defaults])
  @EQ
(merge-pathnames (parse-namestring @i[pathname] nil @i[defaults])
                 @i[defaults])
@Endlisp
in all cases; and the result of @f[enough-namestring] is, roughly speaking,
the shortest reasonable string that will still satisfy this criterion.
@Enddefun

@Defun[Fun {user-homedir-pathname⎇, Args {@optional @i[host]⎇]
@Index[home directory]
Returns a pathname for the user's ``home directory'' on @i[host].
The @i[host] argument
defaults in some appropriate implementation-dependent manner.  The
concept of ``home directory'' is itself somewhat
implementation-dependent, but from the point of view of @clisp it is the
directory where the user keeps personal files such as initialization
files and mail.  If it is impossible to determine this information,
then @nil is returned instead of a pathname; however,
@f[user-homedir-pathname] never returns @nil if the @i[host] argument
is not specified.
This function returns a pathname without any name, type,
or version component (those components are all @nil).
@Enddefun


@Section[Opening and Closing Files]

When a file is @i[opened], a stream object is constructed to serve
as the file system's ambassador to the @xlisp environment;
operations on the stream are reflected by operations on the file
in the file system.  The act of @i[closing] the file (actually,
the stream) ends the association; the transaction with the file
system is terminated, and input/output may no longer be performed
on the stream.  The stream function @Funref[close] may be used
to close a file; the functions described below may be used to open them.
The basic operation is @f[open], but @f[with-open-file] is usually
more convenient for most applications.

@Defun[Fun {open⎇, Args {@i[filename]⎇, Keys {[direction][element-type]⎇,
Morekeys {[if-exists][if-does-not-exist]⎇, SuppressKeyIndex yes]
This returns a stream that is connected to the file specified by @i[filename].
The @i[filename] is the name of the file to be opened; it may be a string,
a pathname, or a stream.  (If the @i[filename] is a stream, then it is not
closed first or otherwise affected; it is used merely to provide a file name
for the opening of a new stream.)

The keyword arguments specify what kind of stream to produce and how
to handle errors:
@keywordlist[open]
@keyword[direction]
This argument specifies whether the stream should handle input, output,
or both.
@subkeywordlist[direction]
@subkeyword[input]
The result will be an input stream.  This is the default.
@endsubkeyword

@subkeyword[output]
The result will be an output stream.
@endsubkeyword

@subkeyword[io]
The result will be a bidirectional stream.
@endsubkeyword

@subkeyword[probe]
The result will be a no-directional stream (in effect, the stream
is created and then closed).  This is useful for determining whether
a file exists without actually setting up a complete stream.
@endsubkeyword
@endsubkeywordlist
@endkeyword

@keyword[element-type]
This argument specifies the type of the unit of transaction for the stream.
Anything that can be recognized as being a finite subtype of
@f[character] or @f[integer] is acceptable.  In particular,
the following types are recognized:
@subkeywordlist[type]
@pseudosubkeyword{@f[string-char]⎇
The unit of transaction is a string-character.
The functions @Funref[read-char] and/or @Funref[write-char] may be
used on the stream.  This is the default.
@endsubkeyword

@pseudosubkeyword{@f[character]⎇
The unit of transaction is any character, not just a string-character.
The functions @Funref[read-char] and/or @Funref[write-char] may be
used on the stream.
@endsubkeyword

@pseudosubkeyword{@f[(unsigned-byte @i[n])]⎇
The unit of transaction is an unsigned byte (a non-negative integer) of size @i[n].
The functions @Funref[read-byte] and/or @Funref[write-byte] may be
used on the stream.
@endsubkeyword

@pseudosubkeyword{@f[unsigned-byte]⎇
The unit of transaction is an unsigned byte (a non-negative integer);
the size of the byte is determined by the file system.
The functions @Funref[read-byte] and/or @Funref[write-byte] may be
used on the stream.
@endsubkeyword

@pseudosubkeyword{@f[(signed-byte @i[n])]⎇
The unit of transaction is a signed byte of size @i[n].
The functions @Funref[read-byte] and/or @Funref[write-byte] may be
used on the stream.
@endsubkeyword

@pseudosubkeyword{@f[signed-byte]⎇
The unit of transaction is a signed byte;
the size of the byte is determined by the file system.
The functions @Funref[read-byte] and/or @Funref[write-byte] may be
used on the stream.
@endsubkeyword

@pseudosubkeyword{@f[bit]⎇
The unit of transaction is a bit (values @f[0] and @f[1]).
The functions @Funref[read-byte] and/or @Funref[write-byte] may be
used on the stream.
@endsubkeyword

@pseudosubkeyword{@f[(mod @i[n])]⎇
The unit of transaction is a non-negative integer less than @i[n].
The functions @Funref[read-byte] and/or @Funref[write-byte] may be
used on the stream.
@endsubkeyword

@subkeyword[default]
The unit of transaction is to be determined by the file system, based
on the file it finds.
The type can be determined by using the function @Funref[stream-element-type].
@endsubkeyword
@endsubkeywordlist
@endkeyword

@keyword[if-exists]
This argument specifies the action to be taken if the @Kwd[direction] is
@Kwd[output] or @Kwd[io] and a file of the specified name already exists.
If the direction is @Kwd[input] or @Kwd[probe], this argument is ignored.
@subkeywordlist[if-exists]
@subkeyword[error]
Signal an error.  This is the default when the version component of
the @i[filename] is not @Kwd[newest].
@endsubkeyword

@subkeyword[new-version]
Create a new file with the same file name, but with a larger version number.
This is the default when the version component of the @i[filename] is @Kwd[newest].
@endsubkeyword

@subkeyword[rename]
Rename the existing file to some other name, and then create a new file
with the specified name.
@endsubkeyword

@subkeyword[rename-and-delete]
Rename the existing file to some other name and then delete it (but
don't expunge it, on those systems that distinguish deletion from
expunging).  Then create a new file with the specified name.
@endsubkeyword

@subkeyword[overwrite]
The existing file is used, and output operations on the stream
will destructively modify the file.
If the @Kwd[direction] is @Kwd[io],
the file is opened in a bidirectional mode that allows both
reading and writing.  The file pointer is initially positioned
at the beginning of the file; however, the file is not truncated
back to length zero when it is opened.
This mode is most useful when
the @Funref[file-position] function can be used on the stream.
@endsubkeyword

@subkeyword[append]
The existing file is used, and output operations on the stream
will destructively modify the file.  The file pointer is
initially positioned at the end of the file.
If the @Kwd[direction] is @Kwd[io],
the file is opened in a bidirectional mode that allows both
reading and writing.
@endsubkeyword

@subkeyword[supersede]
Supersede the existing file.  If possible, the implementation should
arrange not to destroy the old file until the new stream is closed,
against the possibility that the stream will be closed in ``abort'' mode
(see @Funref[close]).
This differs from @Kwd[new-version] in that @Kwd[supersede] creates
a new file with the same name as the old one, rather than a file
name with a higher version number.
@endsubkeyword

@pseudosubkeyword[@false]
Do not create a file or even a stream.
Instead, simply return @false to indicate failure.
@endsubkeyword
@endsubkeywordlist

If the @Kwd[direction] is @Kwd[output] or @Kwd[io]
and the value of @Kwd[if-exists] is @Kwd[new-version],
then the version of the (newly created) file that is opened will
be a version greater than that of any other file in the file system
whose other pathname components are the same as those of @i[filename].

If the @Kwd[direction] is @Kwd[input] or @Kwd[probe]
or the value of @Kwd[if-exists] is not @Kwd[new-version],
@i[and] the version component of the @i[filename] is @Kwd[newest],
then the file opened is that file already existing in the file system
that has a version greater than that of any other file in the file system
whose other pathname components are the same as those of @i[filename].

@Implementation{The various file systems in existence today
have widely differing capabilities.  A given implementation may not
be able to support all of these options in exactly the manner stated.
An implementation is required to recognize all of these option keywords
and to try to do something ``reasonable'' in the context of the host operating
system.  Implementors are encouraged to approximate the semantics specified
here as closely as possible.

As an example, suppose that a file system does not support distinct file
versions and does not distinguish the notions of deletion and expunging
(in some file systems file deletion is reversible until an expunge operation
is performed).  Then @Kwd[new-version] might be treated the same as
@Kwd[rename] or @Kwd[supersede], and @Kwd[rename-and-delete] might
be treated the same as @Kwd[supersede].

If it is utterly impossible for an implementation to handle some option
in a manner close to what is specified here, it may simply signal an error.
The opening of files is an area where complete portability is too much to
hope for; the intent here is simply to make things as portable as possible
by providing specific names for a range of commonly supportable options.⎇
@endkeyword

@keyword[if-does-not-exist]
This argument specifies the action to be taken if
a file of the specified name does not already exist.
@subkeywordlist[if-does-not-exist]
@subkeyword[error]
Signal an error.  This is the default if the @Kwd[direction] is @Kwd[input],
or if the @Kwd[if-exists] argument is @Kwd[overwrite] or @Kwd[append].
@endsubkeyword

@subkeyword[create]
Create an empty file with the specified name, and then proceed as if it
had already existed (but do not perform any processing directed by the
@Kwd[if-exists] argument).
This is the default if the @Kwd[direction] is @Kwd[output]
or @Kwd[io], and the @Kwd[if-exists] argument is anything but @Kwd[overwrite]
or @Kwd[append].
@endsubkeyword

@pseudosubkeyword[@false]
Do not create a file or even a stream.
Instead, simply return @false to indicate failure.
This is the default if the @Kwd[direction] is @Kwd[probe].
@endsubkeyword
@endsubkeywordlist
@endkeyword
@endkeywordlist

When the caller is finished with the stream, it should close the file by
using the @Funref[close] function.  The @Macref[with-open-file]
form does this automatically, and so is preferred for most purposes.
@f[open] should be used only when the control structure of the program
necessitates opening and closing of a file in some way more complex than
provided by @f[with-open-file].  It is suggested that any program that uses
@f[open] directly should use the special form @Specref[unwind-protect] to
close the file if an abnormal exit occurs.
@Enddefun

@Defmac[Fun {with-open-file⎇, Args {(@i[stream] @i[filename] @Mstar<@i[options]>) @mstar<@i[declaration]> @mstar<@i[form]>⎇]
@f[with-open-file]
evaluates the @i[forms] of the body (an implicit @f[progn]) with the variable
@i[stream] bound to a stream that reads or writes the file named by the
value of @i[filename].
The @i[options] are evaluated and are used as keyword arguments to
the function @Funref[open].

When control leaves the body, either normally or abnormally (such as by
use of @Specref[throw]), the file is automatically closed.  If a new
output file is being written, and control leaves abnormally, the file is
aborted and the file system is left, so far as possible, as if the file
had never been opened.  Because @f[with-open-file] always closes the
file, even when an error exit is taken, it is preferred over @f[open] for
most applications.

@i[filename] is the name of the file to be opened; it may be a string,
a pathname, or a stream.
For example:
@lisp
(with-open-file (ifile name :direction :input)
  (with-open-file (ofile (merge-pathname-defaults ifile
						  nil
						  "out")
			 :direction :output
			 :if-exists :supersede)
    (transduce-file ifile ofile)))
@endlisp
@Enddefmac

@Implementation{While @f[with-open-file] tries to automatically close
the stream on exit from the construct, for robustness it is helpful
if the garbage collector can detect discarded streams and automatically
close them.⎇

@Section[Renaming, Deleting, and Other File Operations]

These functions provide a standard interface to operations provided
in some form by most file systems.  It may be that some implementations
of @clisp cannot support them all completely.

@Defun[Fun {rename-file⎇, Args {@i[file] @i[new-name]⎇]
The specified @i[file] is renamed to @i[new-name] (which must be a filename).
The @i[file] may be a string, a pathname, or a stream.  If it is an open stream
associated with a file, then the stream itself and the file associated
with it are affected (if the file system permits).

@f[rename-file] returns three values if successful.  The first value
is the @i[new-name] with any missing components filled in by performing
a @Funref[merge-pathnames] operation using @i[file] as the defaults.
The second value is the @Funref[truename] of the file before it was renamed.
The third value is the @Funref[truename] of the file after it was renamed.

If the renaming operation is not successful, an error is signalled.

It is an error to specify a filename containing a @Kwd[wild] component,
for @i[file] to contain a @nil component where the file system does
not permit a @nil component, or for the result of defaulting missing
components of @i[new-name] from @i[file] to contain a @nil component
where the file system does not permit a @nil component.

@Incompatibility{This corresponds to the function
called @f[renamef] in @maclisp and @lmlisp.
The name @f[renamef] is not used in @clisp
because the convention that a trailing @f[f] means ``file''
conflicts with the use of a trailing @f[f]
for forms related to @Macref[setf].⎇
@Enddefun

@Defun[Fun {delete-file⎇, Args {@i[file]⎇]
The specified @i[file] is deleted.  The @i[file] may be a string, a
pathname, or a stream.  If it is an open stream associated with a file,
then the stream itself and the file associated with it are affected (if
the file system permits), in which case the stream may or may not be
closed immediately, and the deletion may be immediate or delayed until
the stream is explicitly closed, depending on the requirements of the
file system.

@f[delete-file] returns a non-@nil value if successful.
It is left to the discretion of the implementation whether an attempt
to delete a nonexistent file is considered to be successful.
If the deleting operation is not successful, an error is signalled.

It is an error to specify a file name containing a @Kwd[wild] component
or one containing a @nil component where the file system does not
permit a @nil component.
@Incompatibility{This corresponds to the function
called @f[deletef] in @maclisp and @lmlisp.⎇
@Enddefun

@Defun[Fun {probe-file⎇, Args {@i[file]⎇]
This predicate is false if there is no file named @i[file],
and otherwise returns a pathname that is the true name of the file
(which may be different from @i[file] because of file links, version
numbers, or other artifacts of the file system).
Note that if the @i[file] is an open stream associated with a file,
then @f[probe-file] cannot return @nil but will produce the
true name of the associated file.
See @Funref[truename] and the @Kwd[probe] value for the
@Kwdref[F {open⎇, K {direction⎇] argument to @f[open].
@Incompatibility{This corresponds to the function
called @f[probef] in @maclisp and @lmlisp.⎇
@Enddefun

@Defun[Fun {file-write-date⎇, Args {@i[file]⎇]
@i[file] can be a filename or a stream that is open to a file.
This returns the time at which the file was created
or last written as an integer in
universal time format (see section @ref[TIME-SECTION]),
or @false if this cannot be determined.
@Enddefun

@Defun[Fun {file-author⎇, Args {@i[file]⎇]
@i[file] can be a filename or a stream that is open to a file.
This returns the name of the author of the file as a string,
or @false if this cannot be determined.
@Enddefun

@Defun[Fun {file-position⎇, Args {@i[file-stream] @optional @i[position]⎇]
@f[file-position] returns or sets the current position within
a random-access file.

@f[(file-position @i[file-stream])] returns a non-negative integer
indicating the current position within the @i[file-stream], or @false if
this cannot be determined.  The file position at the start of a file will
be zero.  The value returned by @f[file-position] increases monotonically
as input or output operations are performed.  For a character file,
performing a single @Funref[read-char] or @Funref[write-char] operation
may cause the file position to be increased by more than 1 because of
character-set translations (such as translating between the @clisp
@f[#\Newline] character and an external @c[ascii]
carriage-return/line-feed sequence) and other aspects of the
implementation.  For a binary file, every @f[read-byte] or @f[write-byte]
operation increases the file position by 1.

@f[(file-position @i[file-stream] @i[position])] sets the position within
@i[file-stream] to be @i[position].  The @i[position] may be an integer,
or @Kwd[start] for the beginning of the stream, or @Kwd[end] for the end of the
stream.
If the integer is too large or otherwise inappropriate, an error
is signalled (the @Funref[file-length] function returns the length beyond
which @f[file-position] may not access).  An integer returned by
@f[file-position] of one argument should, in general, be acceptable
as a second argument for use with the same file.
With two arguments,
@f[file-position] returns @true if the repositioning was performed
successfully, or @false if it was not (for example,
because the file was not random-access).

@Implementation{Implementations that have character files represented
as a sequence of records of bounded size might choose to encode the
file position as, for example,
@i[record-number]*256+@i[character-within-record].
This is a valid encoding because it increases monotonically as
each character is read or written, though not necessarily by 1 at
each step.  An integer might then be considered ``inappropriate''
as a second argument to @f[file-position] if, when decoded into
record number and character number, it turned out that the
specified record was too short for the specified character number.⎇

@Incompatibility{This corresponds to the function
called @f[filepos] in @maclisp and @lmlisp.⎇
@Enddefun

@Defun[Fun {file-length⎇, Args {@i[file-stream]⎇]
@i[file-stream] must be a stream that is open to a file.
The length of the file is returned as a non-negative integer,
or @false if the length cannot be determined.
For a binary file,
the length is specifically
measured in units of the @Kwd[element-type] specified
when the file was opened (see @Funref[open]).

@Incompatibility{This corresponds to the function
called @f[lengthf] in @maclisp and @lmlisp.⎇
@Enddefun

@Section[Loading Files]

To @i[load] a file is to read through the file, evaluating each form in
it.  Programs are typically stored in files; the expressions in the file
are mostly special forms such as @Macref[defun], @Macref[defmacro],
and @Macref[defvar], which define
the functions and variables of the program.

Loading a compiled (``fasload'') file is similar, except that the file does not
contain text but rather pre-digested expressions created by the
compiler that can be loaded more quickly.

@Defun[Fun {load⎇, Args {@i[filename]⎇, Keys {[verbose][print][if-does-not-exist]⎇]
This function loads the file named by @i[filename] into the @xLisp
environment.  It is assumed that a text (character file) can be
automatically distinguished from an object (binary) file by some appropriate
implementation-dependent means, possibly by the file type.
The defaults for @i[filename] are taken from the variable
@Varref[default-pathname-defaults].
If the @i[filename] (after the merging in of the defaults)
does not explicitly specify a type,
and both text and object types of the file are available in the file system,
@f[load] should
try to select the more appropriate file by some implementation-dependent means.

If the first argument is a stream rather than a pathname,
then @f[load] determines what kind of stream it is and loads
directly from the stream.

The @Kwd[verbose] argument (which defaults to the value of
@Varref[load-verbose]), if true, permits @f[load] to print a message
in the form of a comment (that is, with a leading
semicolon) to @Varref[standard-output] indicating what
file is being loaded and other useful information.

The @Kwd[print] argument (default @nil),
if true, causes the value of each expression
loaded to be printed to @Varref[standard-output].  If a binary file is
being loaded, then what is printed may not reflect precisely the contents
of the source file, but nevertheless some information will be printed.

If a file is successfully loaded, @f[load] always returns a non-@false
value.  If @Kwd[if-does-not-exist] is specified and is @false,
@f[load] just returns @false rather than signalling an error if the file
does not exist.
@Enddefun

@Defvar[Var {load-verbose⎇]
This variable provides the default for the @Kwd[verbose] argument
to @Funref[load].  Its initial value is implementation-dependent.
@Enddefvar


@Section [Accessing Directories]

The following function is a very simple portable primitive for examining
a directory.  Most file systems can support much more powerful
directory-searching primitives, but no two are alike.
It is expected that most implementations of @clisp will extend the
semantics of the @f[directory] function or provide more powerful
primitives.

@Defun[Fun {directory⎇, Args {@i[pathname] @key⎇]
A list of pathnames is returned, one for each
file in the file system that matches the given @i[pathname].
(The @i[pathname] argument may be a pathname, a string,
or a stream associated with a file.)
For a file that matches, the @Funref[truename] appears
in the result list.
If no file matches the @i[pathname], it is not an error;
@f[directory] simply returns @nil, the list of no results.
Keywords such as @Kwd[wild] and @Kwd[newest] may
be used in @i[pathname] to indicate the search space.

@Implementation{It is anticipated that
an implementation may need to provide additional
parameters to control the directory search.  Therefore @f[directory]
is specified to take additional keyword arguments so that implementations
may experiment with extensions,
even though no particular keywords are specified here.

As a simple example of such an extension, for a file system that
supports the notion of cross-directory file links,
a keyword argument @Kwd[links] might, if non-@nil,
specify that such links be included in the result list.⎇
@Enddefun